﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace ReflectionAndMetadata
{
    class ActivatorCreateInstance
    {
        delegate int IntFunc(int x);
        static int Square(int x) => x * x;
        int Cube(int x) => x * x * x;
        public static void Show()
        {
            Delegate staticD = Delegate.CreateDelegate(typeof(IntFunc), typeof(ActivatorCreateInstance), "Square");
            Delegate instanceD = Delegate.CreateDelegate(typeof(IntFunc), new ActivatorCreateInstance(), "Cube");
            Console.WriteLine(staticD.DynamicInvoke(3));
            Console.WriteLine(instanceD.DynamicInvoke(3));
            IntFunc f = (IntFunc)staticD;
            Console.WriteLine(f(3));
        }

        public static void ShowGenericTypes()
        {
            Type closed = typeof(List<int>);
            List<int> list = (List<int>)Activator.CreateInstance(closed)!; // OK

            Type unbound = typeof(List<>);
            //object anError = Activator.CreateInstance(unbound); // Runtime Error
            // 使用 MakeGenericType 可以把没有封闭的泛型变为封闭的泛型。 GetGenericTypeDefinition 方法刚好相反
            Type closedUnbound = unbound.MakeGenericType(typeof(int));

            Type unbound2 = closed.GetGenericTypeDefinition(); //  unbound = unboud2

            Type nullable = typeof(bool?);
            Console.WriteLine(nullable.IsGenericType && nullable.GetGenericTypeDefinition() == typeof(Nullable<>));
            // GetGenericArguments() 获取泛型的泛型参数类型
            Console.WriteLine(closed.GetGenericArguments()[0]); // System.Int32
            Console.WriteLine(nullable.GetGenericArguments()[0]); // System.Boolean
            Console.WriteLine(unbound.GetGenericArguments()[0]); // T 

            
        }

        public static void ReflectingAndInvokingMembers()
        {
            // GetMembers() 方法获取的是当前类和基类中的 public 类型的方法
            /*MemberInfo[] members = typeof(ActivatorCreateInstance).GetMembers();
            foreach (var m in members)
            {
                Console.WriteLine(m);
            }
            //MemberInfo[] memberInfos = typeof(ActivatorCreateInstance).GetMember("Show");
            //Console.WriteLine(memberInfos[0]);
            Console.WriteLine("*******************************");
            // typeof(ActivatorCreateInstance).GetTypeInfo().DeclaredMembers; 获取的是当前类中所有的定义方法，包括 public  和  private 等
            IEnumerable<MemberInfo> membersList = typeof(ActivatorCreateInstance).GetTypeInfo().DeclaredMembers;
            foreach (var m in membersList)
            {
                Console.WriteLine(m);
            }*/

            /* // 获取特殊的成员
             MethodInfo method = typeof(ActivatorCreateInstance).GetTypeInfo().DeclaredMethods.FirstOrDefault(m => m.Name == "ToString" && m.GetParameters().Length == 0)!;

             MethodInfo test = typeof(ActivatorCreateInstance).GetMethod("ToString");
             MethodInfo obj = typeof(object).GetMethod("ToString");
             Console.WriteLine(test.DeclaringType);
             Console.WriteLine(obj.DeclaringType);
             Console.WriteLine(test.ReflectedType);
             Console.WriteLine(obj.ReflectedType);
             Console.WriteLine(test==obj);*/

            //PropertyInfo pi = typeof(Console).GetProperty("Title");
            //Console.WriteLine(pi.GetGetMethod());
            //Console.WriteLine(pi.GetSetMethod());
            //foreach (var item in pi.GetAccessors())
            //{
            //    Console.WriteLine(item);
            //}

            // 使用 RSA 非对称加密
            //byte[] data = { 1, 2, 3, 4, 5 };
            //using(var rsa = new RSACryptoServiceProvider())
            //{
            //    byte[] encrypted = rsa.Encrypt(data, true);
            //    byte[] decrypted = rsa.Decrypt(encrypted, true);
            //}

            //var rsa = new RSACryptoServiceProvider(2048);

            //using (var rsa = new RSACryptoServiceProvider())
            //{
            //    File.WriteAllText("PublicKeyOnly.xml", rsa.ToXmlString(false));
            //    File.WriteAllText("PublicPrivate.xml", rsa.ToXmlString(true));
            //}

            //using (var rsa = new RSACryptoServiceProvider(2048))
            //{
            //    File.WriteAllText("PublicKeyOnly2048.xml", rsa.ToXmlString(false));
            //    File.WriteAllText("PublicPrivate2048.xml", rsa.ToXmlString(true));
            //}

            // 使用上面生成的密钥加解密信息
            //byte[] data = Encoding.UTF8.GetBytes("Message to encrypt");
            //string publicKeyOnly = File.ReadAllText("PublicKeyOnly.xml");
            //string publicPrivate = File.ReadAllText("PublicPrivate.xml");
            //byte[] encrypted, decrypted;
            //using (var rsaPublicOnly = new RSACryptoServiceProvider())
            //{
            //    rsaPublicOnly.FromXmlString(publicKeyOnly);
            //    encrypted = rsaPublicOnly.Encrypt(data, true);
            //    // The next line would throw an exception because you need the private key in order to decrypt
            //    // decrypted = rsaPublicOnly.Decrypt(encrypted, true);
            //}

            //using (var rsaPublicPrivate = new RSACryptoServiceProvider())
            //{
            //    rsaPublicPrivate.FromXmlString(publicPrivate);
            //    decrypted = rsaPublicPrivate.Decrypt(encrypted, true);
            //    Console.WriteLine(Encoding.UTF8.GetString(decrypted));
            //}

            // 数字签名
            byte[] data = Encoding.UTF8.GetBytes("Message to sign");
            byte[] publicKey;
            byte[] signature;
            object hasher = SHA1.Create();

            // Generate a new key pair,then sign the data with it;
            using (var publicPrivate = new RSACryptoServiceProvider())
            {
                signature = publicPrivate.SignData(data, hasher);
                publicKey = publicPrivate.ExportCspBlob(false); // get public key
            }
            // Create a fresh RSA using just the public key,then test the signature.
            using (var publicOnly = new RSACryptoServiceProvider())
            {
                publicOnly.ImportCspBlob(publicKey);
                Console.WriteLine(publicOnly.VerifyData(data,hasher,signature));

                // let's new tamper with the data and recheck the signature;
                data[0] = 0;
                Console.WriteLine(publicOnly.VerifyData(data,hasher,signature));

                // The following throws an exception as we're lacking a private key
                // signature = publicOnly.SignData(data, hasher);
            }

        }

        public static void ShowThread()
        {
            Thread t = new Thread(Go);
            t.Start();
            t.Join(2);
            Console.WriteLine("Thread t has ended!");
        }
        static void Go()
        {
            for (int i = 0; i < 1000; i++)
            {
                Console.Write("Y"); // 
            }
        }
    }
}
